package com.leesche.zcsp.node.pay.sinopay.service.impl;

import com.leesche.zcsp.node.net.service.NetService;
import com.leesche.zcsp.node.pay.sinopay.service.SinopayService;
import com.leesche.zcsp.node.pay.wecha.data.Message;
import com.leesche.zcsp.node.pay.wecha.data.XmlParam;
import com.leesche.zcsp.node.pay.wecha.utils.SignUtil;
import com.leesche.zcsp.node.pay.wecha.utils.XMLUtil;
import com.leesche.zcsp.node.utils.HttpUtil;
import com.leesche.zcsp.node.utils.MD5Util;
import com.leesche.zcsp.node.utils.NetConfig;
import com.leesche.zcsp.node.utils.PayConfig;
import com.leesche.zcsp.node.web.constants.Constants;
import com.leesche.zcsp.node.web.model.*;
import com.leesche.zcsp.node.web.service.*;
import com.leesche.zcsp.node.web.service.impl.data.read.QuerySysMemberCondition;
import com.leesche.zcsp.node.web.service.impl.data.read.SysMemberDto;
import com.leesche.zcsp.node.web.service.impl.data.read.SysUserBusinessInfoDto;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

/**
 * Created by dennies yang on 2016-11-03.
 */
@Service
@SuppressWarnings("all")
public class SinopayServiceImpl implements SinopayService {
    private static final Logger LOGGER = Logger.getLogger(SinopayServiceImpl.class);
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final String INSERT_PAYDETAIL = "insert into t_pub_device_pay_detail (DeviceID, PayType, money, "
            + "Coin, Cash, Quantity, ReceiveTime, UploadTime, userid, CreateTime,recordid) " + "values (#deviceId," +
            "#payType,#money,#coin,#cash,#quantity,#receiveTime,#uploadTime,#userId,#createTime,#recordId);";

    @Autowired
    private NetService netService;
    @Autowired
    private ServOrderService orderService;
    @Autowired
    private PubDeviceService pubDeviceService;
    @Autowired
    private PubDevicePayDetailService payDetailService;
    @Autowired
    private SysMemberService sysMemberService;
    @Autowired
    private PUBConsumptionService pubConsumptionService;


    @Override
    public Message<String> prePay(ServOrder order, String ip, SysUserBusinessInfoDto busiInfoDto, String userAgent,
                                  boolean isMember) {
        TreeMap treeMap = new TreeMap();
        treeMap.put("mch_id", busiInfoDto.getMerchantnumber());
        treeMap.put("out_trade_no", order.getOutTradeNo());
        treeMap.put("body", (order.getCashFee() / 100) + "元" + order.getCoin() + "币");
        treeMap.put("total_fee", String.valueOf(order.getCashFee()));
        treeMap.put("mch_create_ip", ip);
        treeMap.put("nonce_str", SignUtil.getRandomStringByLength(32));

        if (isMember) {
            treeMap.put("notify_url", PayConfig.MEMBERPAY_NOTIFY_URL);
        } else {
            treeMap.put("notify_url", PayConfig.SINOPAY_NOTIFY_URL);
        }

        if (userAgent.equalsIgnoreCase("wechat")) {
            treeMap.put("service", PayConfig.SINOPAY_SERVICE_WECHAT);
            treeMap.put("sub_openid", order.getOpenid());
        } else if (userAgent.equalsIgnoreCase("alipay")) {
            treeMap.put("service", PayConfig.SINOPAY_SERVICE_ALIPAY);
            treeMap.put("branches_no", busiInfoDto.getText1());
        }

        String sign = genSign(treeMap, busiInfoDto.getMerchantkey());
        treeMap.put("sign", sign);

        String xml = genXML(treeMap);
        LOGGER.info("sinopay query string xml=" + xml);

        try {
            long t1 = System.currentTimeMillis();
            String result = HttpUtil.post(PayConfig.SINOPAY_URL, xml.toString(), HttpUtil.getPostHeaders());
            long t2 = System.currentTimeMillis();
            LOGGER.info("翔融预支付耗时" + (t2 - t1) + "毫秒");
            LOGGER.info("翔融预支付返回结果:" + result);
            Map<String, String> map = XMLUtil.parseXml(result);

            String status = map.get("status");
            if (StringUtils.isNotBlank(status) && status.equals("0")) {
                LOGGER.info("status=" + status);
                String result_code = map.get("result_code");
                if (StringUtils.isNotBlank(result_code) && result_code.equals("0")) {
                    String content = "";
                    if (userAgent.equalsIgnoreCase("wechat")) {
                        content = map.get("pay_info");
                    } else if (userAgent.equalsIgnoreCase("alipay")) {
                        content = map.get("code_url");
                    }
                    return Message.success(content, new Object[0]);
                } else {
                    String err_msg = map.get("err_msg");
                    return Message.error(err_msg, new Object[0]);
                }
            } else {
                String message = map.get("message");
                return Message.error(message, new Object[0]);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return Message.error("下单失败!", new Object[0]);
        }
    }

    /**
     * 回调通知处理
     * @param request
     * @return
     */
    @Override
    public String notify(HttpServletRequest request) {
        Date now = new Date();
        XmlParam param = null;
        try {
            param = new XmlParam(request.getInputStream());

            String service = param.getParam("service");
            int payType = 0;
            if (service.equalsIgnoreCase("pay.weixin.jspay")) {
                payType = NetConfig.PAYTYPE_WECHAT;
            } else if (service.equalsIgnoreCase("pay.alipay.native")) {
                payType = NetConfig.PAYTYPE_ALIPAY;
            }

            if (param.getParam("status").equals("0")) {
                String resultCode = param.getParam("result_code");
                if (resultCode.equals("0")) {
                    String out_trade_no = param.getParam("out_trade_no");
                    String transaction_id = param.getParam("transaction_id");
                    String pay_result = param.getParam("pay_result");
                    String pay_info = param.getParam("pay_info");
//                String time_end = param.getParam("time_end");

                    //查询订单
                    ServOrder servOrder = orderService.findServOrderByOrderNo(out_trade_no);
                    //查询设备
                    PubDevice pubDevice = pubDeviceService.selectByPrimaryKey(servOrder.getDeviceid());

                    //更新订单状态及调用出币流程
                    if (servOrder != null && servOrder.getTradeState() != 1 && pubDevice != null) {
                        if (pay_result.equals("0")) {
                            servOrder.setTransactionId(transaction_id);
                            servOrder.setTradeState(Constants.TRADE_STATE_SUCCESS);
                            servOrder.setTradeStateDesc("交易成功");
                            servOrder.setTimeEnd(now);
                            orderService.updateByPrimaryKey(servOrder);

                            //支付成功才出币
                            LOGGER.info("回调通知成功,准备发送指令给设备......");
                            netService.sendClientBuy(pubDevice, servOrder.getCashFee() / 100, servOrder
                                    .getCoin(), payType, servOrder);

                            insertPayDetail(pubDevice, servOrder, payType);
                        } else {
                            servOrder.setTransactionId(transaction_id);
                            servOrder.setTradeState(Constants.TRADE_STATE_PAYERROR);
                            servOrder.setTradeStateDesc(pay_info);
                            servOrder.setTimeEnd(now);
                            orderService.updateByPrimaryKey(servOrder);
                        }
                    }
                }
            }
            return "success";
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "fail";
    }

    /**
     * 会员支付购币回调通知处理
     * @param request
     * @return
     */
    @Override
    public String notifyMemberPay(HttpServletRequest request) {
        Date now = new Date();
        try {
            XmlParam param = new XmlParam(request.getInputStream());

            String service = param.getParam("service");
            int payType = 0;
            if (service.equalsIgnoreCase("pay.weixin.jspay")) {
                payType = NetConfig.PAYTYPE_WECHAT;
            } else if (service.equalsIgnoreCase("pay.alipay.native")) {
                payType = NetConfig.PAYTYPE_ALIPAY;
            }

            if (param.getParam("status").equals("0")) {
                String resultCode = param.getParam("result_code");
                if (resultCode.equals("0")) {
                    String out_trade_no = param.getParam("out_trade_no");
                    String transaction_id = param.getParam("transaction_id");
                    String pay_result = param.getParam("pay_result");
                    String pay_info = param.getParam("pay_info");

                    //查询订单
                    ServOrder servOrder = orderService.findServOrderByOrderNo(out_trade_no);
                    //查询设备
                    PubDevice pubDevice = pubDeviceService.selectByPrimaryKey(servOrder.getDeviceid());

                    //更新订单状态
                    if (servOrder != null && servOrder.getTradeState() != 1 && pubDevice != null) {
                        if (pay_result.equals("0")) {
                            servOrder.setTransactionId(transaction_id);
                            servOrder.setTradeState(Constants.TRADE_STATE_SUCCESS);
                            servOrder.setTradeStateDesc("交易成功");
                            servOrder.setTimeEnd(now);
                            orderService.updateByPrimaryKey(servOrder);

                            LOGGER.info("会员购币支付成功,更新会员表数据...");
                            QuerySysMemberCondition condition = new QuerySysMemberCondition();
                            condition.setAdminid(pubDevice.getAdminid());
                            if (payType == NetConfig.PAYTYPE_WECHAT){
                                condition.setOpenid(servOrder.getOpenid());
                            }else {
                                condition.setAlipayid(servOrder.getOpenid());
                            }
                            SysMemberDto sysMemberDto = sysMemberService.findByCondition(condition);

                            SysMember sysMember = new SysMember(sysMemberDto);
                            sysMember.setCoin(sysMember.getCoin() + servOrder.getCoin());
                            sysMemberService.updateByPrimaryKey(sysMember);

                            PUBConsumption pubConsumption = new PUBConsumption();
                            pubConsumption.setMemberid(sysMember.getMemberid());
                            pubConsumption.setQuantity(servOrder.getCoin());
                            pubConsumption.setCtype(1);
                            pubConsumption.setDeviceid(pubDevice.getDeviceid());
                            pubConsumption.setDevicename(pubDevice.getDevicename());
                            pubConsumption.setPlaceid(pubDevice.getPlaceid());
                            pubConsumption.setResult(1);
                            pubConsumption.setResulttext("成功");
                            pubConsumptionService.insert(pubConsumption);

                            insertPayDetail(pubDevice, servOrder, payType);
                        } else {
                            servOrder.setTransactionId(transaction_id);
                            servOrder.setTradeState(Constants.TRADE_STATE_PAYERROR);
                            servOrder.setTradeStateDesc(pay_info);
                            servOrder.setTimeEnd(now);
                            orderService.updateByPrimaryKey(servOrder);
                        }
                    }
                }
            }
            return "success";
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "fail";
    }

    /**
     * 插入流水表
     * @param pubDevice
     * @param servOrder
     * @param payType
     */
    private void insertPayDetail(PubDevice pubDevice, ServOrder servOrder, int payType) {
        Date now = new Date();
        PubDevicePayDetail detail = new PubDevicePayDetail();
        detail.setDeviceid(pubDevice.getDeviceid());
        detail.setPlaceid(pubDevice.getPlaceid());
        detail.setUserid(pubDevice.getAdminid());
        detail.setPaytype(payType);
        detail.setCoin(servOrder.getCashFee());
        detail.setCash(0);
        detail.setMoney(0);
        detail.setQuantity(1);//未确认
        detail.setCreatetime(now);
        detail.setReceivetime(now);
        detail.setUploadtime(now);
        detail.setRecordid(servOrder.getCreatetime().getTime());

        try {
            payDetailService.insert(detail);
        } catch (Exception e) {
            LOGGER.error("写入交易明细数据失败,保存SQL到临时文件! ", e);

            //写数据库失败,生成SQL 保存到临时文件
            String sql = INSERT_PAYDETAIL.replace("#deviceId", String.valueOf(detail.getDeviceid()))
                                         .replace("#payType", String.valueOf(detail.getPaytype()))
                                         .replace("#money", String.valueOf(detail.getMoney()))
                                         .replace("#coin", String.valueOf(detail.getCoin()))
                                         .replace("#cash", String.valueOf(detail.getCash()))
                                         .replace("#quantity", String.valueOf(detail.getQuantity()))
                                         .replace("#receiveTime", "'" + sdf.format(detail.getReceivetime()) + "'")
                                         .replace("#uploadTime", "'" + sdf.format(detail.getUploadtime()) + "'")
                                         .replace("#userId", String.valueOf(detail.getUserid()))
                                         .replace("#createTime", "'" + sdf.format(detail.getCreatetime()) + "'")
                                         .replace("#recordId", String.valueOf(detail.getRecordid()));
            LOGGER.info("INSERT_PAYDETAIL: " + sql);

            File file = new File("/data/backup/pay_detail.txt");
            try {
                if (!file.exists()) {
                    file.createNewFile();
                }

                FileOutputStream os = new FileOutputStream(file, true); //如果追加方式用true
                os.write((sql + "\n\n").getBytes("UTF-8"));
                os.close();
            } catch (FileNotFoundException e1) {
                LOGGER.error(e1.getMessage(), e1);
            } catch (IOException e2) {
                LOGGER.error(e2.getMessage(), e2);
            }
        }
    }

    /**
     * 根据参数map,生成md5 加密的签名
     * @param map 参数,必须为 TreeMap
     * @return
     */
    private String genSign(TreeMap map, String key) {
        StringBuffer buffer = new StringBuffer();
        Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry e = iter.next();
            buffer.append(e.getKey()).append("=").append(e.getValue()).append("&");
        }
        buffer.append("key=").append(key);

        String sign = MD5Util.MD5Encode(buffer.toString(), "utf-8");
        return sign.toUpperCase();
    }

    /**
     * 生成 xml 字符串参数
     * @param map
     * @return
     */
    private String genXML(TreeMap map) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<xml>");
        Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry e = iter.next();
            buffer.append("<").append(e.getKey()).append(">").append(e.getValue()).append("</").append(e.getKey())
                  .append(">");
        }
        buffer.append("</xml>");
        return buffer.toString();
    }

/*
    @Override
    public Message<String> onScanPay(ServOrder order, String ip) {
        TreeMap treeMap = new TreeMap();
        treeMap.put("service", PayConfig.SINOPAY_SERVICE_ALIPAY);
        treeMap.put("mch_id", PayConfig.SINOPAY_MCHID_TEST);
        treeMap.put("branches_no", PayConfig.SINOPAY_ALI_BRANCH_NO_TEST);
        treeMap.put("out_trade_no", order.getOutTradeNo());
        treeMap.put("body", (order.getCashFee() / 100) + "元" + order.getCoin() + "币");
        treeMap.put("total_fee", "1");//String.valueOf(order.getCashFee())
        treeMap.put("mch_create_ip", ip);
        treeMap.put("notify_url", PayConfig.SINOPAY_NOTIFY_URL_TEST);
        treeMap.put("nonce_str", SignUtil.getRandomStringByLength(32));

        String sign = genSign(treeMap, PayConfig.SINOPAY_MD5_KEY_TEST);
        treeMap.put("sign", sign);

        String xml = genXML(treeMap);
        LOGGER.info("sinopay onScan query string xml=" + xml);

        try {
            long t1 = System.currentTimeMillis();
            String result = HttpUtil.post2(PayConfig.SINOPAY_URL_TEST, xml.toString(), HttpUtil.getPostHeaders());
            long t2 = System.currentTimeMillis();
            LOGGER.info("请求翔融预支付耗时" + (t2 - t1) + "毫秒");
            LOGGER.info("翔融预支付返回结果:" + result);

            Map<String, String> map = XMLUtil.parseXml(result);

            String status = map.get("status");
            if (StringUtils.isNotBlank(status) && status.equals("0")) {
//                LOGGER.info("status=" + status);
                String result_code = map.get("result_code");
                if (StringUtils.isNotBlank(result_code) && result_code.equals("0")) {
//                    LOGGER.info("result_code=" + result_code);
                    String code_url = map.get("code_url");
                    return Message.success(code_url, new Object[0]);
                } else {
                    String err_msg = map.get("err_msg");
                    return Message.error(err_msg, new Object[0]);
                }
            } else {
                String message = map.get("message");
                return Message.error(message, new Object[0]);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return Message.error("下单失败!", new Object[0]);
        }
    }
*/

}
